
package SSF.OS;

/** Generic base class for pools of objects.  By using an object pool, 
  * an alert modeler may be able to avoid calling new() to create new
  * objects.  This can save significant amounts of time, especially in 
  * parallel code, since new() has the potential to create lock contention
  * for the heap.<p> 
  *
  * To create a pool of objects of class Foo, one might use an anonymous 
  * inner class:
  *
  * <pre>
  *         ObjectPool fooPool = new ObjectPool() {
  *            public Object makeObject() { return new Foo(); };
  *         };
  * </pre>
  * 
  * Then you would replace calls to <pre>new Foo()</pre> by calls to 
  * <pre>fooPool.obtain()</pre>.  If the pool is empty, <pre>obtain</pre>
  * simply calls <pre>new()</pre>, so little time is wasted.  <p>
  *
  * To get the benefits of using a pool, you must also try to 
  * return instances of Foo to the pool after their last use, by calling
  * <pre>fooPool.recycle(deadFoo)</pre>.  Remember to 'clean up' each 
  * object before you recycle it, by removing all references to it from 
  * elsewhere in your data.  <p>
  *
  * If you forget to recycle an object, it's okay: the Java garbage 
  * collector will eventually do so for you.  <p>
  *
  * If you specify a pool that's too large, and don't make use of the objects 
  * awaiting recycling, you may increase memory consumption by preventing 
  * the Java garbage collector from doing its job.  Try to choose a max  
  * pool size that reflects the typical imbalance at any point between 
  * recyclers and consumers of Objects.  
  */
public abstract class ObjectPool {

  public static final int DEFAULT_MIN_POOL_SIZE = 4;
  public static final int DEFAULT_MAX_POOL_SIZE = 64;

  public abstract Object makeObject();

  public ObjectPool() {
   this(DEFAULT_MIN_POOL_SIZE, DEFAULT_MAX_POOL_SIZE);
  }

  public ObjectPool(int min, int max) {
    data = new Object[capacity = min];
    current = 0;
    limit = max;
  }

  public Object obtain() {
     return (current==0?makeObject():data[--current]);
  }

  public void recycle(Object obj) {
    if (current==capacity) {
      if (capacity >= limit) return; // overflow
      Object[] newdata = new Object[Math.min(limit,capacity*2)];
      System.arraycopy(data,0,newdata,0,capacity);
      for (int n=0; n<capacity; n++) data[n] = null;
      data = newdata;
      capacity = data.length;
    }
    data[current++] = obj;
  }

  private int current, capacity, limit;
  private Object[] data;
}
